package com.tc.shiro.realm;

import com.tc.shiro.model.LoginReqParam;
import com.tc.shiro.model.LoginResParam;
import com.tc.shiro.model.OperatorInfo;
import com.tc.shiro.model.PermissionModel;
import com.tc.shiro.constants.MerchantWebappConstants;
import com.tc.shiro.exceptions.PortalAuthenticationException;
import com.tc.shiro.service.LoginService;
import com.tc.shiro.service.OperatorService;
import com.tc.shiro.service.RoleService;
import com.tc.shiro.session.RedisSessionDao;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class MerchantAuthorizingReam extends AuthorizingRealm {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisSessionDao redisSessionDao;

    @Autowired
    private RoleService roleService;

    @Autowired
    private LoginService loginService;

    @Autowired
    private OperatorService operatorService;

    private final Logger logger = LoggerFactory.getLogger(MerchantAuthorizingReam.class);

    /**
     * 授权: 方法上标注了RequiresPermissions注解,然后PermissionAnnotationHandler.assertAuthorized  判断当用户已经登录,
     * 然后调用 subject.checkPermission
     *
     * spring 配置文件中配置 AuthorizationAttributeSourceAdvisor 开启shiro注解支持
     * AuthorizationAttributeSourceAdvisor 构造方法中加了一下拦截器，
     *
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        OperatorInfo operatorInfo = (OperatorInfo) principals.getPrimaryPrincipal();
        try {
            logger.info("loginName={},开始授权", operatorInfo.getOperator());
            String redisKey = MerchantWebappConstants.PERMISSIONS_SESSION_NAME + operatorInfo.getMercNo() + "_"+ operatorInfo.getRoleNo();
            Object obj = redisTemplate.boundValueOps(redisKey).get();
            List<String> permissions = null;
            if (obj != null) {
                permissions = (List<String>) obj;
            }
            if (permissions == null) {
                logger.info("获取不到缓存中的权限信息redisKey:{}",redisKey);
                List<PermissionModel> permissionList = roleService.queryPermissionByRoleNo(operatorInfo.getRoleNo(),operatorInfo.getMercNo());
                if (permissionList!=null && !permissionList.isEmpty()) {
                    permissions = new ArrayList<String>();
                    // 获取权限列表
                    iteratePermiss(permissions, permissionList);
                    // 保存权限到缓存，不放到session中是因为，权限会被别人管理员修改，放到缓存方便管理员删除
                    long timeout = Long.parseLong("1800000");
                    redisTemplate.boundValueOps(redisKey).set(permissions, timeout, TimeUnit.MILLISECONDS);
                }
            }
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            // 将上边查询到授权信息填充到simpleAuthorizationInfo对象中
            simpleAuthorizationInfo.addStringPermissions(permissions);
            logger.info("loginName={},授权结束", operatorInfo.getOperator());
            return simpleAuthorizationInfo;
        } catch (Exception e) {
            logger.error("操作员={},授权失败,e={}", e);
        }
        return null;
    }

    /**
     * 认证  登录时候调用 subject.login(token)
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;
        String loginName = (String) token.getPrincipal();
		logger.info("loginName={},ip={},开始认证", loginName, usernamePasswordToken.getHost());
        String pwd = new String((char[]) token.getCredentials());
        LoginReqParam loginReqParam = new LoginReqParam();
        loginReqParam.setLoginName((String) token.getPrincipal());
        loginReqParam.setLoginPwd(pwd);
        loginReqParam.setCustomerIp(usernamePasswordToken.getHost());
        LoginResParam loginResParam;
        try {
            loginResParam = loginService.login(loginReqParam);
            String respCode = loginResParam.getRespCode();
            if ("0000".equals(respCode)) {
                // 1、根据登录名查询数据库中的操作员信息
                OperatorInfo operatorInfo = operatorService.queryOperaterInfo(loginName, null);
                // 2、将用户上传的密码设置到AuthenticationInfo中
                SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(operatorInfo, pwd,this.getName());
                Session session = SecurityUtils.getSubject().getSession();
                session.setAttribute("loginResParam", loginResParam);
                logger.info("loginName={},认证结束", loginName);
                // 3、返回AuthenticationInfo信息
                return simpleAuthenticationInfo;
            } else {
                throw new PortalAuthenticationException(loginResParam.getRespCode(),loginResParam.getRespMsg());
            }
        } catch (Exception e) {
            logger.error("登录名={},登录出错,e={}", loginName, e);
            throw new PortalAuthenticationException("9999", "系统错误");
        }

    }

    private void iteratePermiss(List<String> permissions, List<PermissionModel> permissionList) {
        if (permissions != null && permissionList != null && !permissionList.isEmpty()) {
            for (PermissionModel model : permissionList) {
                String permission = model.getPermissions();
                if (StringUtils.isNotBlank(permission)) {
                    permissions.add(permission);
                }
            }
        }
    }

}